home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SNNSV32.ZIP / SNNSv3.2 / kernel / sources / kr_td.c < prev    next >
C/C++ Source or Header  |  1994-04-25  |  25KB  |  747 lines

  1. /*****************************************************************************
  2.   FILE           : kr_td.c
  3.   SHORTNAME      : 
  4.   SNNS VERSION   : 3.2
  5.  
  6.   PURPOSE        : SNNS-Kernel Learning Functions for Time Delay networks
  7.   NOTES          : with following learning functions:
  8.                    - Backpropagation
  9.  
  10.   AUTHOR         : Oliver Schnabel, Guenter Mamier
  11.   DATE           : 
  12.  
  13.   CHANGED BY     : Michael Vogt, Guenter Mamier
  14.   IDENTIFICATION : @(#)kr_td.c    1.8 4/12/94
  15.   SCCS VERSION   : 1.8
  16.   LAST CHANGE    : 4/12/94
  17.  
  18.              Copyright (c) 1990-1994  SNNS Group, IPVR, Univ. Stuttgart, FRG
  19.  
  20. ******************************************************************************/
  21.  
  22. #include <stdio.h>
  23. #include <math.h>
  24. #include <values.h>
  25.  
  26.  
  27. #include "kr_typ.h"     /*  Kernel Types and Constants  */
  28. #include "kr_const.h"     /*  Constant Declarators for SNNS-Kernel  */
  29. #include "kr_def.h"     /*  Default Values  */
  30. #include "kernel.h"     /*  kernel function prototypes  */
  31. #include "kr_mac.h"     /*  Kernel Macros   */
  32. #include "kr_newpattern.h"
  33.  
  34. #include "kr_td.ph"
  35.  
  36.  
  37.  
  38. /*****************************************************************************
  39.   FUNCTION : initializeTDBackprop
  40.  
  41.   PURPOSE  : initialize the learning algorithm TD-backprop
  42.   NOTES    :
  43.  
  44.   RETURNS  :
  45.   UPDATE   : 19.02.1993 
  46. ******************************************************************************/
  47. static krui_err initializeTDBackprop(void)
  48. {
  49.   register FlagWord      flags;
  50.   register struct Link   *link_ptr;
  51.   register struct Unit   *unit_ptr;
  52.   register struct Site   *site_ptr; 
  53.  
  54.   /*  set unit's bias to zero  */
  55.   FOR_ALL_UNITS( unit_ptr ){
  56.       flags = unit_ptr->flags;
  57.  
  58.       if ( (unit_ptr->flags & UFLAG_IN_USE) == UFLAG_IN_USE){
  59.       if (flags & UFLAG_SITES){ /*  unit has sites  */
  60.           FOR_ALL_SITES_AND_LINKS( unit_ptr, site_ptr, link_ptr )
  61.           link_ptr->value_b = 
  62.               link_ptr->value_c = 
  63.               unit_ptr->value_a = 
  64.                   unit_ptr->value_b = 
  65.                   unit_ptr->value_c = (FlintType) 0;
  66.       }else{        /* TD-units have no sites: direct links */
  67.           if (flags & UFLAG_DLINKS){ /*  unit has direct links */
  68.           FOR_ALL_LINKS( unit_ptr, link_ptr ) 
  69.               link_ptr->value_b = 
  70.               link_ptr->value_c = 
  71.                   unit_ptr->value_a = 
  72.                   unit_ptr->value_b = 
  73.                       unit_ptr->value_c = (FlintType) 0;
  74.           }
  75.       } /* else */
  76.       } /* if */
  77.   } /* FOR_ALL_UNITS */
  78.   return( KRERR_NO_ERROR );
  79. }
  80.  
  81.  
  82. /*****************************************************************************
  83.   FUNCTION : propagateTDNetForward
  84.  
  85.   PURPOSE  : topological TimeDelay forward propagation
  86.   NOTES    : needs only the weight matrix of one receptive field for 
  87.          propagating one pattern through the net
  88.          If the provided pattern_no is < 0, no pattern is loaded into
  89.              the input layer but all other layers are propagated as usual
  90.   RETURNS  :
  91.   UPDATE   : 19.02.1993
  92. ******************************************************************************/
  93. void  propagateTDNetForward(int pattern_no, int sub_pat_no)
  94.   register struct Unit    *unit_ptr;
  95.   register struct Link    *link_ptr;
  96.   register Patterns       in_pat;
  97.   register TopoPtrArray   topo_ptr;
  98.   int                     i;
  99.  
  100.   if (pattern_no >= 0){
  101.       /*  calculate startaddress for input pattern array  */
  102.  
  103.       in_pat = kr_getSubPatData(pattern_no,sub_pat_no,INPUT,NULL);
  104.       topo_ptr = topo_ptr_array;
  105.  
  106.       /* copy pattern into input unit's activation and calculate output of the 
  107.      input units. */
  108.       /* order of the topoptrarray: input-, hidden- and then outputunits */    
  109.  
  110.       unit_ptr = *++topo_ptr;
  111.       while (unit_ptr != (struct Unit *) NULL){
  112.       /*  topo_ptr points to a (topological sorted) unit stucture 
  113.           (input units first)  */
  114.  
  115.       if (unit_ptr->out_func == OUT_IDENTITY){
  116.           /*  identity output function: don't call the output function  */
  117.           unit_ptr->Out.output = unit_ptr->act = *in_pat++;
  118.       }else{
  119.           /*  no identity output function: calculate unit's output also  */
  120.           unit_ptr->Out.output = 
  121.           (*unit_ptr->out_func) (unit_ptr->act = *in_pat++);
  122.       } /*if*/
  123.       unit_ptr = *++topo_ptr;
  124.       }
  125.   }else{
  126.       /* set unit_ptr and topo_ptr as if an input pattern was provided */
  127.       topo_ptr = topo_ptr_array;
  128.       unit_ptr = *++topo_ptr;
  129.       while (unit_ptr != (struct Unit *) NULL)
  130.       {
  131.       unit_ptr = *++topo_ptr;
  132.       }
  133.   }
  134.       
  135.   /* Propagate input to hidden, hidden to hidden and hidden to output */
  136.  
  137.   for (i=0; i<2; i++){
  138.       unit_ptr = *++topo_ptr;
  139.       while (unit_ptr != NULL){
  140.       /*  initialization for propagating hidden units  */
  141.       /*  clear error values */
  142.       unit_ptr->Aux.flint_no = 0.0;
  143.  
  144.       if (UNIT_HAS_DIRECT_INPUTS(unit_ptr)){
  145.           /* this is a reference unit, initialize link weight change */
  146.           /* and counter of link usage */
  147.           FOR_ALL_LINKS(unit_ptr, link_ptr){
  148.           link_ptr->value_b = link_ptr->value_c = 0.0;
  149.           }
  150.       }
  151.  
  152.       /* reset bias-change and td-step-counter before each lerning epoch */
  153.       unit_ptr->value_b = unit_ptr->value_c = 0.0;
  154.  
  155.       unit_ptr->act = (*unit_ptr->act_func) (unit_ptr);
  156.       if (unit_ptr->out_func == OUT_IDENTITY){
  157.           /*  identity output function: don't call the output function  */
  158.           unit_ptr->Out.output = unit_ptr->act;
  159.       }else{
  160.           /*  no identity output function: calculate unit's output also  */
  161.           unit_ptr->Out.output = (*unit_ptr->out_func) (unit_ptr->act);
  162.       }      
  163.       unit_ptr = *++topo_ptr;
  164.       }
  165.   }
  166. } /*endfunction*/
  167.  
  168.  
  169.  
  170. /*****************************************************************************
  171.   FUNCTION : propagateTDNetBackward
  172.  
  173.   PURPOSE  : Time Delay Backward error propagation (topological).
  174.   NOTES    : Start calculating the average of the corresponding links in 
  175.              all TD-steps. This average is used to update the links of the 
  176.          1st. receptive field.
  177.   RETURNS  : network error
  178.   UPDATE   : 19.02.1993
  179. ******************************************************************************/
  180. static    float propagateTDNetBackward(int pattern_no, int sub_pat_no,
  181.                      float learn_parameter, 
  182.                      float delta_max)
  183.     register struct Link   *link_ptr;
  184.     register struct Site   *site_ptr;
  185.     register struct Unit   *unit_ptr, *unit_ptr1 ;
  186.     register struct Unit   *ref_unit;
  187.     register Patterns      out_pat;
  188.     register float         error,  sum_error,  eta,  devit, learn_error;
  189.     register TopoPtrArray  topo_ptr;
  190.     int                    last_log_layer, i;
  191.     int                    size;
  192.  
  193.     sum_error = 0.0;        /*  reset network error  */
  194.     eta = learn_parameter;    /*  store learn_parameter in CPU register  */
  195.  
  196.     /*  calculate address of the output pattern (with number pattern_no + 1) */
  197.  
  198.     topo_ptr = topo_ptr_array + (no_of_topo_units + 2);
  199.     last_log_layer = (*topo_ptr)->lln;
  200.     out_pat = kr_getSubPatData(pattern_no,sub_pat_no,OUTPUT,&size);
  201.     out_pat += size;
  202.  
  203.     /* calculate output units only: begin at the end of topo_pointer_array */
  204.     unit_ptr = *topo_ptr;
  205.     while (unit_ptr != (struct Unit *) NULL){
  206.     devit = *(--out_pat) - unit_ptr->Out.output; /*  calc. devitation */
  207.  
  208.     if ( (float) fabs( devit ) <= delta_max ){
  209.         unit_ptr = *--topo_ptr;
  210.         continue;
  211.     }
  212.  
  213.     sum_error += devit * devit; /*  sum up the error of the network  */
  214.  
  215.     /* calculate error for output units     */
  216.     /* output layer cannot have time delay structure, so no 
  217.        distinction is necessary*/
  218.     error = devit * (unit_ptr->act_deriv_func) ( unit_ptr ); 
  219.  
  220.     /* calc. the error for adjusting weights and bias of pred. units  */
  221.     learn_error = eta * error; 
  222.  
  223.     /* adjust bias value  */
  224.     unit_ptr->value_b += learn_error;
  225.     unit_ptr->value_c += 1.0;
  226.  
  227.     if (UNIT_HAS_DIRECT_INPUTS( unit_ptr )){ /* the unit has direkt links */
  228.         /* error must be saved for each unit of the hiddenlayer */
  229.         FOR_ALL_LINKS( unit_ptr, link_ptr ){
  230.         /* adjust link weights and calc. sum of errors of pred. units*/
  231.         link_ptr->to->Aux.flint_no += link_ptr->weight * error;
  232.         link_ptr->value_b += learn_error * link_ptr->to->Out.output;
  233.         link_ptr->value_c += 1.0;
  234.         }
  235.     }else{ /* the unit has sites: not necessary for TD-Network  */
  236.         FOR_ALL_SITES_AND_LINKS( unit_ptr, site_ptr, link_ptr ){
  237.         /* adjust link weights and calc. sum of errors of pred. units */
  238.         link_ptr->to->Aux.flint_no += link_ptr->weight * error;
  239.         link_ptr->weight += learn_error * link_ptr->to->Out.output;
  240.             }
  241.     }
  242.      
  243.     unit_ptr = *--topo_ptr; 
  244.     } /* while */
  245.  
  246.  
  247.     /*  calculate hidden units only. add the weight changes of all receptive 
  248.     fields ; stored for every linkin the Linkstructure value_c of only the 
  249.     first recept. field! 
  250.     */
  251.   
  252.     unit_ptr = *--topo_ptr;
  253.     while (unit_ptr != (struct Unit *) NULL){
  254.     /* calc. the error of the hidden units */
  255.     error = (unit_ptr->act_deriv_func) (unit_ptr) * unit_ptr->Aux.flint_no;
  256.     
  257.     /* calc. the error for adjusting weights and bias of pred. units */
  258.     learn_error = eta * error;
  259.  
  260.  
  261.     if (unit_ptr->TD.td_connect_typ == 1){
  262.         /* this is a time delay connection type layer */
  263.  
  264.         ref_unit = *(unit_ptr->TD.my_topo_ptr + unit_ptr->TD.target_offset);
  265.         /*    adjust bias value  */
  266.         ref_unit->value_b += learn_error;
  267.         ref_unit->value_c += 1.0;
  268.     
  269.         if (UNIT_HAS_DIRECT_INPUTS( ref_unit )){
  270.         /*  the unit has direkt links    */
  271.         
  272.         FOR_ALL_LINKS( ref_unit, link_ptr ) {
  273.             /* adjust link weights and calc. sum of err of pred. units*/
  274.             /* unit_ptr1 points to the actual predecessor unit, 
  275.                determined by the actual link */
  276.             unit_ptr1 = *(link_ptr->to->TD.my_topo_ptr 
  277.                   + unit_ptr->TD.source_offset);
  278.         
  279.             if (IS_HIDDEN_UNIT (unit_ptr1)) {
  280.             /* this unit is a hidden unit: add the error from 
  281.                previous units dependent on type of this predecessor 
  282.                unit   */
  283.             (unit_ptr1)->Aux.flint_no += link_ptr->weight * error;
  284.             }
  285.             /* immediately updating the links cannot fit for TD 
  286.                Networks! Add the the delta(ij) of all td_steps in the 
  287.                Linkarray(value_c) of the first recept. field  */
  288.             link_ptr->value_b += learn_error * (unit_ptr1)->Out.output;
  289.             link_ptr->value_c += 1.0;
  290.         }
  291.         }
  292.     }else{
  293.         /* fully connected layers */
  294.         /* immediately update of all physical links */
  295.         unit_ptr->bias += learn_error;
  296.  
  297.         if (UNIT_HAS_DIRECT_INPUTS( unit_ptr )){
  298.         /*  the unit has direkt links  */
  299.         /* error must be saved for each unit of the hiddenlayer */
  300.         FOR_ALL_LINKS( unit_ptr, link_ptr ){
  301.             /* adjust link weights and calc. sum of err of pred units*/
  302.             if (IS_HIDDEN_UNIT (link_ptr->to))
  303.             link_ptr->to->Aux.flint_no += link_ptr->weight * error;
  304.           
  305.             link_ptr->weight += learn_error * link_ptr->to->Out.output;
  306.         }
  307.         }else{ /* the unit has sites: not necessary for TD-Network  */
  308.         FOR_ALL_SITES_AND_LINKS( unit_ptr, site_ptr, link_ptr ){
  309.             /*  adjust link weights and calc. sum of errors of the 
  310.             predecessor units */
  311.             if (IS_HIDDEN_UNIT (link_ptr->to)) 
  312.             link_ptr->to->Aux.flint_no += link_ptr->weight * error;
  313.             link_ptr->weight += learn_error * link_ptr->to->Out.output;
  314.         }
  315.         }
  316.     }
  317.     unit_ptr = *--topo_ptr;
  318.     } /* while */
  319.   
  320.  
  321.     /* update receptive fields: propagate and calculate all featureunits of 
  322.        the first td-step of each layer.   */
  323.     /* topo_ptr points to the NULL pointer between input and hidden units */
  324.  
  325.     for (i=0; i<2; i++){
  326.     unit_ptr = *++topo_ptr;
  327.     while (unit_ptr != NULL){
  328.         if (unit_ptr->TD.td_connect_typ==1 && 
  329.         UNIT_HAS_DIRECT_INPUTS(unit_ptr)){
  330.         /* this is a reference unit of a time delay layer */
  331.  
  332.         /* update bias of reference unit by average bias change */
  333.         unit_ptr->bias += unit_ptr->value_b / unit_ptr->value_c;
  334.  
  335.         FOR_ALL_LINKS( unit_ptr, link_ptr ){ 
  336.             /* store average linkweigth changes of all Td-steps */
  337.             link_ptr->weight += link_ptr->value_b / link_ptr->value_c;
  338.         } /*for_all_links*/
  339.         }
  340.         unit_ptr = *++topo_ptr;
  341.     }
  342.     }
  343.     return( sum_error );    /*  return the error of the network */
  344. }
  345.  
  346.  
  347.  
  348. /*****************************************************************************
  349.   FUNCTION : LEARN_TDbackprop
  350.  
  351.   PURPOSE  : Time Delay Backpropagation Learning Function
  352.   NOTES    : Input Parameters:   1 : learning parameter
  353.                                  2 : delta max
  354.  
  355.              Output Parameters:  1 : error of the network (sum of all cycles)
  356.  
  357.   RETURNS  :
  358.   UPDATE   : 19.02.1993
  359. ******************************************************************************/
  360. krui_err  LEARN_TDbackprop( int start_pattern, int end_pattern, 
  361.                float parameterInArray[], int NoOfInParams,
  362.                float * *parameterOutArray, int *NoOfOutParams )
  363.  
  364. {
  365.     static  float  OutParameter[1]; /* OutParameter[0] stores learning error */
  366.     int   i, ret_code, pattern_no, sub_pat_no;
  367.     int   j;
  368.     struct Unit *unit_ptr;
  369.  
  370.     if (NoOfUnits == 0)  
  371.     return( KRERR_NO_UNITS ); /*  No Units defined    */
  372.     if (NoOfInParams < 1)    /*  #  has to be changed (must be 2) # */
  373.     return( KRERR_PARAMETERS ); /*  Not enough input parameters  */
  374.  
  375.     *NoOfOutParams = 1;     /* One return value is available (the learning error)*/
  376.     *parameterOutArray = OutParameter; /* set the output parameter reference  */
  377.     ret_code = KRERR_NO_ERROR;  /*  reset return code  */
  378.  
  379.     if (NetModified || (TopoSortID != TOPOLOGIC_LOGICAL)){
  380.     /*  Net has been modified or topologic array isn't initialized */
  381.     /*  check the topology of the network  */
  382.     /* first: save the logical layer numbers, restore them after check */
  383.     FOR_ALL_UNITS(unit_ptr)
  384.         unit_ptr -> Aux.int_no = unit_ptr -> lln;
  385.     ret_code = kr_topoCheck();
  386.  
  387.     FOR_ALL_UNITS(unit_ptr)
  388.         unit_ptr -> lln = unit_ptr -> Aux.int_no;
  389.     if (ret_code < KRERR_NO_ERROR)  
  390.         return( ret_code );    /*  an error has occured  */
  391.     if (ret_code < 2)  
  392.         return( KRERR_NET_DEPTH ); /* the network has less then 2 layers */
  393.  
  394.     /*    count the no. of I/O units and check the patterns  */
  395.     ret_code = kr_IOCheck();
  396.     if (ret_code < KRERR_NO_ERROR)  
  397.         return( ret_code );
  398.  
  399.     ret_code = kr_topoSort( TOPOLOGIC_LOGICAL );
  400.     if ((ret_code != KRERR_NO_ERROR) && (ret_code != KRERR_DEAD_UNITS))
  401.         return( ret_code );
  402.  
  403. #ifdef DEBUG
  404.     /* M.V. */
  405.     j=1;
  406.     while (krui_setCurrentUnit(j) == KRERR_NO_ERROR) {
  407.         printf("Unit %d: lln = %d, lun = %d\n",j,
  408.            kr_getUnitPtr(j) -> lln, kr_getUnitPtr(j) -> lun);
  409.         j++;
  410.     }
  411. #endif
  412.  
  413.     NetModified = FALSE;
  414.     }
  415.  
  416.     if (NetInitialize || LearnFuncHasChanged){
  417.     /*  Net has been modified or initialized, initialize TDbackprop now */
  418.     ret_code = initializeTDBackprop();
  419.     if (ret_code != KRERR_NO_ERROR)  
  420.         return( ret_code );
  421.     }
  422.  
  423.  
  424.     /* compute the necessary sub patterns */
  425.  
  426.     KernelErrorCode = kr_initSubPatternOrder(start_pattern,end_pattern);
  427.     if(KernelErrorCode != KRERR_NO_ERROR)
  428.     return (KernelErrorCode);
  429.  
  430.  
  431.     NET_ERROR(OutParameter) = 0.0;    /* reset network error value  */
  432.  
  433.     while(kr_getSubPatternByOrder(&pattern_no,&sub_pat_no)){
  434.  
  435.     propagateTDNetForward(pattern_no,sub_pat_no); /* Forward propagation */
  436.  
  437.     /*  Backward propagation  */
  438.     /*  1st parameter is the learning parameter
  439.         2nd parameter is the max. devitation between output pattern and
  440.         the output of the output unit (delta max)
  441.         */
  442.     NET_ERROR( OutParameter ) +=
  443.         propagateTDNetBackward(pattern_no,sub_pat_no,
  444.                    LEARN_PARAM1( parameterInArray ),
  445.                    LEARN_PARAM2( parameterInArray ) );
  446.     }
  447.  
  448.     return( ret_code );
  449. }
  450.  
  451.  
  452.  
  453. /*****************************************************************************
  454.   FUNCTION : LEARN_TDBP_McClelland
  455.  
  456.   PURPOSE  : Time Delay Backpropagation Learning Function With McClelland
  457.              Error function: E = sum(log(1-(oi-ti)^2))
  458.  
  459.   NOTES    : Input Parameters:   1 : learning parameter
  460.                                  2 : delta max
  461.  
  462.              Output Parameters:  1 : error of the network (sum of all cycles)
  463.  
  464.   RETURNS  :
  465.   UPDATE   : 19.02.1993
  466. ******************************************************************************/
  467. krui_err  LEARN_TDBP_McClelland( int start_pattern, int end_pattern, 
  468.                 float parameterInArray[], int NoOfInParams,
  469.                 float * *parameterOutArray, int *NoOfOutParams )
  470.  
  471. {
  472.     static  float  OutParameter[1]; /* OutParameter[0] stores learning error*/
  473.     int   i, ret_code, pattern_no, sub_pat_no;
  474.     int   j;
  475.     struct Unit *unit_ptr;
  476.  
  477.     if (NoOfUnits == 0)  
  478.     return( KRERR_NO_UNITS ); /*  No Units defined    */
  479.     if (NoOfInParams < 1)    /*  #  has to be changed (must be 2) # */
  480.     return( KRERR_PARAMETERS ); /*  Not enough input parameters  */
  481.  
  482.     *NoOfOutParams = 1;    /* One return value is available (the learning error)*/
  483.     *parameterOutArray = OutParameter; /* set the output parameter reference */
  484.     ret_code = KRERR_NO_ERROR;  /*  reset return code  */
  485.  
  486.     if (NetModified || (TopoSortID != TOPOLOGIC_LOGICAL)){
  487.     /*  Net has been modified or topologic array isn't initialized */
  488.     /*  check the topology of the network  */
  489.     /* first: save the logical layer numbers, restore them after check */
  490.     FOR_ALL_UNITS(unit_ptr)
  491.         unit_ptr -> Aux.int_no = unit_ptr -> lln;
  492.     ret_code = kr_topoCheck();
  493.  
  494.     FOR_ALL_UNITS(unit_ptr)
  495.         unit_ptr -> lln = unit_ptr -> Aux.int_no;
  496.     if (ret_code < KRERR_NO_ERROR)  
  497.         return( ret_code );    /*  an error has occured  */
  498.     if (ret_code < 2)  
  499.         return( KRERR_NET_DEPTH ); /* the network has less then 2 layers */
  500.  
  501.     /* count the no. of I/O units and check the patterns  */
  502.     ret_code = kr_IOCheck();
  503.     if (ret_code < KRERR_NO_ERROR)  
  504.         return( ret_code );
  505.  
  506.     ret_code = kr_topoSort( TOPOLOGIC_LOGICAL );
  507.     if ((ret_code != KRERR_NO_ERROR) && (ret_code != KRERR_DEAD_UNITS))
  508.         return( ret_code );
  509.  
  510. #ifdef DEBUG
  511.     /* M.V. */
  512.     j=1;
  513.     while (krui_setCurrentUnit(j) == KRERR_NO_ERROR) {
  514.         printf("Unit %d: lln = %d, lun = %d\n",  j,
  515.            kr_getUnitPtr(j) -> lln, kr_getUnitPtr(j) -> lun);
  516.         j++;
  517.     }
  518. #endif
  519.  
  520.     NetModified = FALSE;
  521.     }
  522.  
  523.     if (NetInitialize || LearnFuncHasChanged){
  524.     /*  Net has been modified or initialized, initialize TDbackprop now  */
  525.     ret_code = initializeTDBackprop();
  526.     if (ret_code != KRERR_NO_ERROR)  
  527.         return( ret_code );
  528.     }
  529.  
  530.  
  531.     /* compute the necessary sub patterns */
  532.  
  533.     KernelErrorCode = kr_initSubPatternOrder(start_pattern,end_pattern);
  534.     if(KernelErrorCode != KRERR_NO_ERROR)
  535.     return (KernelErrorCode);
  536.  
  537.  
  538.     NET_ERROR(OutParameter) = 0.0;    /* reset network error value  */
  539.  
  540.     while(kr_getSubPatternByOrder(&pattern_no,&sub_pat_no)){
  541.  
  542.     propagateTDNetForward(pattern_no,sub_pat_no); /*  Forward propagation */
  543.  
  544.     /*  Backward propagation  */
  545.     /*  1st parameter is the learning parameter
  546.         2nd parameter is the max. devitation between output pattern and
  547.         the output of the output unit (delta max)
  548.         */
  549.     NET_ERROR( OutParameter ) +=
  550.         propagateTDNetBackMcClelland(pattern_no,sub_pat_no,
  551.                      LEARN_PARAM1( parameterInArray ),
  552.                      LEARN_PARAM2( parameterInArray ) );
  553.     }
  554.  
  555.     return( ret_code );
  556. }
  557.  
  558.  
  559. /*****************************************************************************
  560.   FUNCTION : propagateTDNetBackMcClelland
  561.  
  562.   PURPOSE  : Time Delay Backward error propagation (topological).
  563.   NOTES    : Start calculating the average of the corresponding links in 
  564.              all TD-steps. This average is used to update the links of the 
  565.          1st. receptive field.
  566.   RETURNS  : network error
  567.   UPDATE   : 19.02.1993
  568. ******************************************************************************/
  569. static    float propagateTDNetBackMcClelland(int pattern_no, int sub_pat_no,
  570.                        float learn_parameter,
  571.                        float delta_max)
  572.     register struct Link   *link_ptr;
  573.     register struct Site   *site_ptr;
  574.     register struct Unit   *unit_ptr, *unit_ptr1 ;
  575.     register struct Unit   *ref_unit;
  576.     register Patterns      out_pat;
  577.     register float         error,  sum_error,  eta,  devit, learn_error;
  578.     register TopoPtrArray  topo_ptr;
  579.     int                    last_log_layer, i;
  580.     int                    size;
  581.  
  582.  
  583.     sum_error = 0.0;        /*  reset network error  */
  584.     eta = learn_parameter;    /*  store learn_parameter in CPU register  */
  585.  
  586.     /*  calculate address of the output pattern (with number pattern_no + 1) */
  587.  
  588.     topo_ptr = topo_ptr_array + (no_of_topo_units + 2);
  589.     last_log_layer = (*topo_ptr)->lln;
  590.     out_pat = kr_getSubPatData(pattern_no,sub_pat_no,OUTPUT,&size);
  591.     out_pat += size;
  592.  
  593.     /* calculate output units only: begin at the end of topo_pointer_array */
  594.     unit_ptr = *topo_ptr;
  595.     while (unit_ptr != (struct Unit *) NULL){
  596.     devit = *(--out_pat) - unit_ptr->Out.output; /*  calc. devitation */
  597.  
  598.     if ( (float) fabs( devit ) <= delta_max ){
  599.         unit_ptr = *--topo_ptr;
  600.         continue;
  601.     }
  602.  
  603.     sum_error += -log10(1- fabs(devit)); /* sum up error of the network */
  604.  
  605.     /* calculate error for output units     */
  606.     /* output layer cannot have time delay structure, so no 
  607.        distinction is necessary*/
  608.     error = log10(1- fabs(devit)) * (unit_ptr->act_deriv_func) (unit_ptr); 
  609.     if(devit > 0) error = -error;
  610.  
  611.     /* calc. error for adjusting weights and bias of predecessor units */
  612.     learn_error = eta * error; 
  613.  
  614.     /* adjust bias value  */
  615.     unit_ptr->value_b += learn_error;
  616.     unit_ptr->value_c += 1.0;
  617.  
  618.     if (UNIT_HAS_DIRECT_INPUTS( unit_ptr )){
  619.         /*  the unit has direkt links  */
  620.         /* error must be saved for each unit of the hiddenlayer */
  621.         FOR_ALL_LINKS( unit_ptr, link_ptr ){
  622.         /* adjust link weights and calc. sum of errors of pred. units*/
  623.         link_ptr->to->Aux.flint_no += link_ptr->weight * error;
  624.         link_ptr->value_b += learn_error * link_ptr->to->Out.output;
  625.         link_ptr->value_c += 1.0;
  626.         }
  627.     }else{ /* the unit has sites: not necessary for TD-Network  */
  628.         FOR_ALL_SITES_AND_LINKS( unit_ptr, site_ptr, link_ptr ){
  629.         /* adjust link weights and calc. sum of errors of 
  630.            predecessor units */
  631.         link_ptr->to->Aux.flint_no += link_ptr->weight * error;
  632.         link_ptr->weight += learn_error * link_ptr->to->Out.output;
  633.             }
  634.     }
  635.      
  636.     unit_ptr = *--topo_ptr; 
  637.     } /* while */
  638.  
  639.  
  640.     /*  calculate hidden units only. add the weightchanges of all receptive 
  641.     fields ; stored for every link in the Linkstructure value_c of only 
  642.     the first recept. field! 
  643.     */
  644.   
  645.     unit_ptr = *--topo_ptr;
  646.     while (unit_ptr != (struct Unit *) NULL){
  647.     /* calc. the error of the hidden units */
  648.     error = (unit_ptr->act_deriv_func) (unit_ptr) * unit_ptr->Aux.flint_no;
  649.     
  650.     /* calc. error for adjusting weights and bias of predecessor units */
  651.     learn_error = eta * error;
  652.  
  653.  
  654.     if (unit_ptr->TD.td_connect_typ == 1){
  655.         /* this is a time delay connection type layer */
  656.  
  657.         ref_unit = *(unit_ptr->TD.my_topo_ptr + unit_ptr->TD.target_offset);
  658.         /*    adjust bias value  */
  659.         ref_unit->value_b += learn_error;
  660.         ref_unit->value_c += 1.0;
  661.     
  662.         if (UNIT_HAS_DIRECT_INPUTS( ref_unit )){
  663.         /*  the unit has direkt links    */
  664.         
  665.         FOR_ALL_LINKS( ref_unit, link_ptr ){
  666.             /* adjust link weights and calc. sum of err of pred. units*/
  667.             /* unit_ptr1 points to the actual predecessor unit, 
  668.                determined by the actual link */
  669.             unit_ptr1 = *(link_ptr->to->TD.my_topo_ptr 
  670.                   + unit_ptr->TD.source_offset);
  671.         
  672.             if (IS_HIDDEN_UNIT (unit_ptr1)){
  673.             /* this unit is a hidden unit: add the error from 
  674.                previous units dependent on type of this predecessor 
  675.                unit   */
  676.             (unit_ptr1)->Aux.flint_no += link_ptr->weight * error;
  677.             }
  678.             /* immediately updating the links cannot fit for TD 
  679.                Networks! Add the the delta(ij) of all td_steps in the 
  680.                Linkarray(value_c) of the first recept. field  */
  681.             link_ptr->value_b += learn_error * (unit_ptr1)->Out.output;
  682.             link_ptr->value_c += 1.0;
  683.         }
  684.         }
  685.     }else{
  686.         /* fully connected layers */
  687.         /* immediately update of all physical links */
  688.         unit_ptr->bias += learn_error;
  689.  
  690.         if (UNIT_HAS_DIRECT_INPUTS( unit_ptr )){
  691.         /*  the unit has direkt links  */
  692.         /* error must be saved for each unit of the hiddenlayer */
  693.         FOR_ALL_LINKS( unit_ptr, link_ptr ){
  694.             /* adjust link weights and calc. sum of 
  695.                errors of predecessor units  */
  696.             if (IS_HIDDEN_UNIT (link_ptr->to))
  697.             link_ptr->to->Aux.flint_no += link_ptr->weight * error;
  698.           
  699.             link_ptr->weight += learn_error * link_ptr->to->Out.output;
  700.         }
  701.         }else{/* the unit has sites: not necessary for TD-Network  */
  702.         FOR_ALL_SITES_AND_LINKS( unit_ptr, site_ptr, link_ptr ){
  703.             /*  adjust link weights and calc. sum of errors of the 
  704.             predecessor units */
  705.             if (IS_HIDDEN_UNIT (link_ptr->to)) 
  706.             link_ptr->to->Aux.flint_no += link_ptr->weight * error;
  707.             link_ptr->weight += learn_error * link_ptr->to->Out.output;
  708.         }
  709.         }
  710.     }
  711.     unit_ptr = *--topo_ptr;
  712.     } /* while */
  713.   
  714.  
  715.     /* update receptive fields: propagate and calculate all featureunits of 
  716.        the first td-step of each layer.   */
  717.     /* topo_ptr points to the NULL pointer between input and hidden units */
  718.  
  719.     for (i=0; i<2; i++){
  720.     unit_ptr = *++topo_ptr;
  721.     while (unit_ptr != NULL){
  722.         if (unit_ptr->TD.td_connect_typ==1 && 
  723.         UNIT_HAS_DIRECT_INPUTS(unit_ptr)){
  724.         /* this is a reference unit of a time delay layer */
  725.  
  726.         /* update bias of reference unit by average bias change */
  727.         unit_ptr->bias += unit_ptr->value_b / unit_ptr->value_c;
  728.  
  729.         FOR_ALL_LINKS( unit_ptr, link_ptr ){ 
  730.             /* store average linkweigth changes of all Td-steps */
  731.             link_ptr->weight += link_ptr->value_b / link_ptr->value_c;
  732.         } /*for_all_links*/
  733.         }
  734.         unit_ptr = *++topo_ptr;
  735.     }
  736.     }
  737.     return( sum_error );/*  return the error of the network */
  738. }
  739.  
  740.  
  741.  
  742.  
  743.  
  744.